﻿#region Copyright(C) 2010-2010 NCS Pte. Ltd. All rights reserved.
// ==================================================================================================
// Copyright(C) 2010 NCS Pte. Ltd. All rights reserved.
//
// SYSTEM NAME	    : iConnect .Net Application Framework
// COMPONENT ID	    : NCS.IConnect.Core.Wcf
// COMPONENT DESC   : Core components for WCF.	
//
// CREATED DATE/BY  : 18 Aug 2010 / Gao Ye
//
// REVISION HISTORY :	
// DATE/BY			SR#/CS/PM#/OTHERS		DESCRIPTION OF CHANGE
// ==================================================================================================
#endregion

using NCS.IConnect.Core.Instrumentation;
using System;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.Threading;

namespace NCS.IConnect.Core.ApplicationContexts.Wcf
{
    /// <summary>
    /// The custom <see cref="ICallContextInitializer"/> to receive context sent from client side.
    /// </summary>
    public class ContextReceiveCallContextInitializer : ICallContextInitializer
    {
        /// <summary>
        /// Implement to participate in cleaning up the thread that invoked the operation.
        /// </summary>
        /// <param name="correlationState">The correlation object returned from the <see cref="M:System.ServiceModel.Dispatcher.ICallContextInitializer.BeforeInvoke(System.ServiceModel.InstanceContext,System.ServiceModel.IClientChannel,System.ServiceModel.Channels.Message)"/> method.</param>
        public void AfterInvoke(object correlationState)
        {
            object[] initialStates = correlationState as object[];
            if (null == initialStates)
            {
                return;
            }
            ContextItemCollection initialContext = initialStates[0] as ContextItemCollection;
            ApplicationContext.Current.ContextLocator.Clear();
            ApplicationContext.Current.ContextLocator.AttachContext(initialContext,ApplicationContext.Current.ContextAttachBehavior);

            Thread.CurrentThread.CurrentUICulture =(CultureInfo) initialStates[1];
            Thread.CurrentThread.CurrentCulture = (CultureInfo)initialStates[2];
            ActivityContext.Current = initialStates[3] as ActivityContext;
        }

        /// <summary>
        /// Implement to participate in the initialization of the operation thread.
        /// </summary>
        /// <param name="instanceContext">The service instance for the operation.</param>
        /// <param name="channel">The client channel.</param>
        /// <param name="message">The incoming message.</param>
        /// <returns>
        /// A correlation object passed back as the parameter of the <see cref="M:System.ServiceModel.Dispatcher.ICallContextInitializer.AfterInvoke(System.Object)"/> method.
        /// </returns>
        public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message)
        {
            try
            {
                ActivityContext originalContext = ActivityContext.Current;
                if (message.Headers.FindHeader(ActivityContext.MessageHeaderName, Constants.Namespace) > -1)
                { 
                    ActivityContext activityContext = message.Headers.GetHeader<ActivityContext>(ActivityContext.MessageHeaderName, Constants.Namespace);
                    ActivityContext.Current = activityContext;
                }

                ContextItemCollection initialContext = ApplicationContext.Current.ContextLocator.GetCurrentContext();
                CultureInfo currentUICulture = Thread.CurrentThread.CurrentUICulture;
                CultureInfo currentCulture = Thread.CurrentThread.CurrentCulture;

                if (ApplicationContext.Current.UICultureContextItem == null)
                {
                    ApplicationContext.Current.UICulture = CultureInfo.CurrentUICulture;
                }
                if (ApplicationContext.Current.CultureContextItem == null)
                {
                    ApplicationContext.Current.Culture = CultureInfo.CurrentCulture;
                }
                if (ApplicationContext.Current.TimeZoneContextItem == null)
                {
                    ApplicationContext.Current.TimeZone = TimeZoneInfo.Local;
                }

                ContextItemCollection context = null;
                if (message.Version.Envelope == EnvelopeVersion.Soap11 || message.Version.Envelope == EnvelopeVersion.Soap12)
                {
                    if (message.Headers.FindHeader(ApplicationContext.ContextHeaderLocalName, ApplicationContext.ContextHeaderNamespace) < 0)
                    {
                        return new object[] { initialContext, currentUICulture, currentCulture, originalContext };
                    }
                    context = message.Headers.GetHeader<ContextItemCollection>(ApplicationContext.ContextHeaderLocalName, ApplicationContext.ContextHeaderNamespace);
                }
                else 
                {
                    if (!message.Properties.Keys.Contains(HttpRequestMessageProperty.Name))
                    {
                        return new object[] { initialContext, currentUICulture, currentCulture, originalContext };
                    }
                    HttpRequestMessageProperty requestProperty = (HttpRequestMessageProperty)message.Properties[HttpRequestMessageProperty.Name];
                    if (!requestProperty.Headers.AllKeys.Contains(ApplicationContext.ContextHttpHeaderName))
                    {
                        return new object[] { initialContext, currentUICulture, currentCulture, originalContext };
                    }
                    context = SerializationUtil.Deserialize(requestProperty.Headers[ApplicationContext.ContextHttpHeaderName]);
                }
                ApplicationContext.Current.ContextLocator.AttachContext(context, ApplicationContext.Current.ContextAttachBehavior);
                Thread.CurrentThread.CurrentUICulture = ApplicationContext.Current.UICulture;
                Thread.CurrentThread.CurrentCulture = ApplicationContext.Current.Culture;
                return new object[] { initialContext, currentUICulture, currentCulture, originalContext };               
            }
            catch(Exception exceptionMessage)
            {
                try
                {
                    EventLog myLog = new EventLog();
                    if (!EventLog.SourceExists("WCF Event Log"))
                    {
                        EventLog.CreateEventSource("WCF Event Log", "Application");
                    }

                    myLog.Source = "WCF Event Log";
                    myLog.WriteEntry(exceptionMessage.ToString());
                }
                catch { }             
            }
            return null;
        }
    }
}